package com.atguigu.gmall.activity.listener;

import com.atguigu.gmall.activity.mapper.SeckillGoodsMapper;
import com.atguigu.gmall.activity.util.CacheHelper;
import com.atguigu.gmall.activity.util.DateUtil;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.model.activity.UserRecode;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Date;
import java.util.List;

/**
 * @author: 李旭
 * @create: 2021-09-17 14:09
 * <p>
 * 营销活动  监听器
 **/
@Component
public class ActivityListener {

    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    //将DB中数据压入缓存
    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue(value = MqConst.QUEUE_TASK_1, durable = "true", autoDelete = "false"),
                    exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),
                    key = {MqConst.ROUTING_TASK_1}
            )
    })
    public void receiverDataToRedisMessage(Message message, Channel channel) {
        try {
            //将DB中数据压入缓存 select * from seckill_goods where stock_count > 0
            QueryWrapper queryWrapper = new QueryWrapper<SeckillGoods>();
            //1:查询DB中秒杀商品
            //1.1:  当天的
            queryWrapper.eq("DATE_FORMAT(start_time,'%Y-%m-%d')",
                    DateUtil.formatDate(new Date()));
            //1.2:  有库存  greater e
            queryWrapper.gt("stock_count", "0");
            //1.3:  审核通过的
            queryWrapper.eq("status", "1");
            List<SeckillGoods> seckillGoodsList = seckillGoodsMapper.selectList(queryWrapper);
            //2:写到缓存中
            seckillGoodsList.forEach(seckillGoods -> {
                //2.1: 缓存中已经存在了的  表示继续秒杀  不用再压入一次了
                //Map h  = new HashMap  h.put(hk,hv)   h:常量  hk:skuId.toString  hv:SeckillGoods
                if (!redisTemplate.opsForHash().hasKey(RedisConst.SECKILL_GOODS,
                        seckillGoods.getSkuId().toString())) {
                    //2.2：缓存五大数据类型： Hash类型（散列类型）  秒杀商品 商品中属性 剩余库存
                    redisTemplate.opsForHash().put(RedisConst.SECKILL_GOODS, seckillGoods.getSkuId().toString()
                            , seckillGoods);
                    //2.3: 能解决超卖问题吗？不能解决 （重大待解决问题）
                    // 将秒杀商品压入缓存中的List类型
                    String[] ids = buildSkuIds(seckillGoods.getStockCount(), seckillGoods.getSkuId());
                    redisTemplate.opsForList().leftPushAll(RedisConst.SECKILL_STOCK_PREFIX
                            + seckillGoods.getSkuId(), ids);
                    //2.4:状态位  一发送消息  多个接收的
                    redisTemplate.convertAndSend("seckillpush",
                            seckillGoods.getSkuId() + ":1");
                }
            });
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //组装成一个skuId的数组
    private String[] buildSkuIds(Integer stockCount, Long skuId) {
        String[] ids = new String[stockCount];
        for (Integer i = 0; i < stockCount; i++) {
            ids[i] = skuId.toString();
        }
        return ids;
    }

    //开始秒杀商品
    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue(value = MqConst.QUEUE_SECKILL_1, durable = "true", autoDelete = "false"),
                    exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_Seckill),
                    key = {MqConst.ROUTING_SECKILL_1}
            )
    })
    public void receiverMessage(UserRecode userRecode,Message message, Channel channel) {
        try {
            System.out.println("userRecode:" + userRecode.getUserId());

            //1.校验状态位
            Object status = CacheHelper.get(userRecode.getSkuId().toString());
            if(!"1".equals(status)){
                //MQ 删除消息
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                return;
            }
            //2、校验此用户是否第一次购买  使用Redis记录一下  没有来过 设置一下  来过就不设置了
            Boolean flag = redisTemplate.opsForValue().setIfAbsent(
                    RedisConst.SECKILL_USER + userRecode.getUserId(), "1112");
            if(!flag){
                //来过了
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                return;
            }
            //3、开始抢购
            Object o = redisTemplate.opsForList().rightPop(
                    RedisConst.SECKILL_STOCK_PREFIX + userRecode.getSkuId());
            if(null != o){
                //3.1 抢购成功 文档上放入的对象是 OrderRecode  现在 UserRecode
                redisTemplate.opsForValue().set(
                        RedisConst.SECKILL_ORDERS + userRecode.getUserId(),userRecode);
            }else{
                //3.2抢购失败
                redisTemplate.convertAndSend("seckillpush",
                        userRecode.getSkuId() + ":0");
            }
            //不写了
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
